/***********************************************
This file is part of the AMonSys project (http://code.google.com/p/amonsys/).

    AMonSys is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    AMonSys is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with AMonSys.  If not, see <http://www.gnu.org/licenses/>.
**********************************************/
package asterisk

import (
	"net";
	"bytes";
	"os";
	"strings";
	"strconv";
	"fmt";
	"./config"
)

type Peer struct {
	IP	[]string;
	Name	[]string;
	Number	[]string;
	Status	[]string;
}

type Channel struct {
	App		[]string;
	BridgedChannel	[]string;
	CallerIDnum	[]string;
	Channel		[]string;
	Duration	[]string;
	Extension	[]string;
	State		[]string;
}

func SearchEvent(s *bytes.Buffer, ev string) bool {
	var res bool;
	str := bytes.Split(s.Bytes(),[]byte("\r\n"),-1);
	for i:=0; i<cap(str); i++ {
		chk := bytes.NewBuffer(str[i]);
		if chk.Len() >= cap([]byte(ev)) {
			a := bytes.NewBuffer(chk.Bytes()[0:cap([]byte(ev))]);
			if a.String() == ev {
				res = true;
			}
		}
	}
	return res;
}

func ApmsLogin(conn *net.TCPConn, buf []byte, usr string, pass string,ApmsConf config.ApmsConfig) bool {
	var (
		res	bool;
		ra	[]byte;
	)
	conn.Write([]byte("Action: Login\nUsername: "+usr+"\nSecret: "+pass+"\nEvents: off\n\n"));
	for{
		nr,err := conn.Read(buf);
		if err != nil {
			res = false;
			conn.Close();
			break;
		}
		ra = bytes.Add(ra,buf[0:nr]);
		retorno := bytes.NewBuffer(ra);
		chk := SearchEvent(retorno, "Message: Authentication accepted");
		if chk == true {
			res = true;
			break;
		}
	}
	return res;
}

func ApmsLogout(conn *net.TCPConn, buf []byte){
	conn.Write([]byte("Action: Logoff\r\n\r\n"));
	for {
		_,err := conn.Read(buf);
		if err != nil { break; }
	}
	conn.Close();
}

func ApmsPeers(conn *net.TCPConn, buf []byte,ApmsConf config.ApmsConfig) Peer {
	var (
		ra	[]byte;
		Ramal	Peer;
		ramal	string;
		peer	string;
		ip	string;
		cid	string;
	)
	conn.Write([]byte("Action: SIPpeers\n\n"));
	for{
		nr,err := conn.Read(buf);
		if err != nil {
			if err.String() == "EOF" {os.Exit(1);}
			error := config.LogAsterisk(err.String(),ApmsConf.LogFolder)
			fmt.Print(error)
		}
		ra = bytes.Add(ra,buf[0:nr]);
		retorno := bytes.NewBuffer(ra);
		chk := SearchEvent(retorno, "ListItems:");
		if chk == true { break;}
	}
	bufra := bytes.Split(ra,[]byte("\r\n"),-1);
	for i:=0; i<cap(bufra); i++ {
		chk := bytes.Split(bufra[i],[]byte(": "),-1);
		if cap(chk) == 2 {
			item := bytes.NewBuffer(chk[0]);
			value := bytes.NewBuffer(chk[1]);
			switch item.String() {
				case "ObjectName":
					ramal = value.String();
				case "IPaddress":
					if value.String() != "-none-" {
						if len(peer) == 0 {
							peer = ramal;
						} else {
							peer = peer+","+ramal;
						}
						if len(ip) == 0 {
							ip = value.String();
						} else {
							ip = ip+","+value.String();
						}
					}
			}
		}
	}
	Ramal.Number = strings.Split(peer,",",-1);
	Ramal.IP = strings.Split(ip,",",-1);
	if len(Ramal.Number) >= 1 && Ramal.Number[0] != "" {
		for i:=0 ; i<len(Ramal.Number); i++ {
			conn.Write([]byte("Action: SIPshowpeer\nPeer: "+Ramal.Number[i]+"\n\n"));
			ra = make([]byte,0);
			for{
				nr,err := conn.Read(buf);
				if err != nil {
					if err.String() == "EOF" {os.Exit(1);}
					error := config.LogAsterisk(err.String(),ApmsConf.LogFolder)
					fmt.Print(error)
				}
				ra = bytes.Add(ra,buf[0:nr]);
				retorno := bytes.NewBuffer(ra);
				chk := SearchEvent(retorno, "Parkinglot:");
				if chk == true { break;}
			}
			bufra = bytes.Split(ra,[]byte("\r\n"),-1);
			for i:=0; i<cap(bufra); i++ {
				chk := bytes.Split(bufra[i],[]byte(": "),-1);
				if cap(chk) == 2 {
					item := bytes.NewBuffer(chk[0]);
					value := bytes.NewBuffer(chk[1]);
					if item.String() == "Callerid" {
						pCid := strings.Split(value.String(),"\"",-1);
						if cid == "" {
							cid = pCid[1];
						} else {
							cid = cid + "," + pCid[1];
						}
					}
				}
			}
		}
	}
	Ramal.Name = strings.Split(cid,",",-1);
return Ramal;
}

func ApmsChannels(conn *net.TCPConn, buf []byte,ApmsConf config.ApmsConfig) Channel {
	var (
		ra		[]byte;
		Canal		Channel;
		app		string;
		bridgedChannel	string;
		callerIDnum	string;
		channel		string;
		duration	string;
		extension	string;
		state		string;
	)
	conn.Write([]byte("Action: CoreShowChannels\n\n"));
	for{
		nr,err := conn.Read(buf);
		if err != nil {
			if err.String() == "EOF" {os.Exit(1);}
			error := config.LogAsterisk(err.String(),ApmsConf.LogFolder)
			fmt.Print(error)
		}
		ra = bytes.Add(ra,buf[0:nr]);
		retorno := bytes.NewBuffer(ra);
		chk := SearchEvent(retorno, "ListItems");
		if chk == true { break; }
	}
	bufra := bytes.Split(ra,[]byte("\r\n"),-1);
	for i:=0; i<cap(bufra); i++ {
		chk := bytes.Split(bufra[i],[]byte(": "),-1);
		if cap(chk) == 2 {
			item := bytes.NewBuffer(chk[0]);
			value := bytes.NewBuffer(chk[1]);
			switch item.String() {
				case "Application":
					valor := "";
					if value.String() == "" { valor = " "; } else {valor = value.String();}
					if len(app) == 0 {
						app = valor;
					} else {
						app = app+","+valor;
					}
				case "BridgedChannel":
					valor := "";
					if value.String() == "" { valor = " "; } else {valor = value.String();}
					if len(bridgedChannel) == 0 {
						bridgedChannel = valor;
					} else {
						bridgedChannel = bridgedChannel+","+valor;
					}
				case "CallerIDnum":
					valor := "";
					if value.String() == "" { valor = " "; } else {valor = value.String();}
					if len(callerIDnum) == 0 {
						callerIDnum = valor;
					} else {
						callerIDnum = callerIDnum+","+valor;
					}
				case "Channel":
					valor := "";
					if value.String() == "" { valor = " "; } else {valor = value.String();}
					if len(channel) == 0 {
						channel = valor;
					} else {
						channel = channel+","+valor;
					}
				case "Duration":
					valor := "";
					if value.String() == "" { valor = " "; } else {valor = value.String();}
					if len(duration) == 0 {
						duration = config.ValorToTime(valor);
					} else {
						duration = duration+","+config.ValorToTime(valor);
					}
				case "Extension":
					valor := "";
					if value.String() == "" { valor = " "; } else {valor = value.String();}
					if len(extension) == 0 {
						extension = valor;
					} else {
						extension = extension+","+valor;
					}
				case "ChannelState":
					valor := "";
					if value.String() == "" { valor = " "; } else {valor = value.String();}
					if len(state) == 0 {
						state = valor;
					} else {
						state = state+","+valor;
					}
			}
		}
	}
	Canal.App = strings.Split(app,",",-1);
	Canal.BridgedChannel = strings.Split(bridgedChannel,",",-1);
	Canal.CallerIDnum = strings.Split(callerIDnum,",",-1);
	Canal.Channel = strings.Split(channel,",",-1);
	Canal.Duration = strings.Split(duration,",",-1);
	Canal.Extension = strings.Split(extension,",",-1);
	Canal.State = strings.Split(state,",",-1);
	return Canal;
}

func SearchChannel(c Channel, p string, n string) string {
	var (
		channel		string;
		status		string;
		ext		string;
	)
	for i:=0; i<len(c.Channel); i++ {
		p1 := strings.Split(c.Channel[i],"/",-1);
		if p1[1][0:len(p)] == p {
			status = c.State[i];
			switch	(status){
				case "4":
					status = "rOut";
					ext = c.Extension[i];
				case "5":
					switch (c.App[i][0:3]){
						case "App":
							status = "rIn";
							for i:=0; i<len(c.CallerIDnum); i++ {
								ext = c.CallerIDnum[i];
							}
					}
				case "6":
					switch (c.App[i][0:3]){
						case "App":
							status = "In";
							for i:=0; i<len(c.CallerIDnum); i++ {
								ext = c.CallerIDnum[i];
							}
						default:
							status = "Out";
							for i:=0; i<len(c.CallerIDnum); i++ {
								ext = c.Extension[i];
							}
					}
			}
			channel = status+"|"+ext+"|"+c.Channel[i]+"|"+c.BridgedChannel[i]+"|"+c.Duration[i];
			break;
		}
	}
	if channel == "" {
		channel = p+","+n+";";
	} else {
		channel = p+","+n+","+channel+";";
	}
	return channel;
}

func (p *Peer) AllPeers(ApmsConn *net.TCPConn,ApmsBuf []byte,ApmsConf config.ApmsConfig) (string,string){
	var (
		MainPeers	string;
		MainQPeer	string;
	)
	if len(p.Number) >= 1 && p.Number[0] != "" {
		Canais := ApmsChannels(ApmsConn,ApmsBuf,ApmsConf);
		allPeers := strconv.Itoa(len(p.Number))+";";
		if len(Canais.CallerIDnum) >= 1 && Canais.CallerIDnum[0] != "" {
			for i:=0; i<len(p.Number); i++ {
				if p.Number[i] != ApmsConf.QueuePeer {
					allPeers = allPeers+SearchChannel(Canais, p.Number[i], p.Name[i]);
				} else {
					MainQPeer = ApmsConf.QueueShow+";"+SearchChannel(Canais, p.Number[i], p.Name[i]);
				}
			}
			MainPeers = allPeers;
		} else {
			for i:=0; i<len(p.Number); i++ {
				if p.Number[i] != ApmsConf.QueuePeer {
					allPeers = allPeers+p.Number[i]+","+p.Name[i]+";";
				} else {
					MainQPeer = ApmsConf.QueueShow+";"+p.Number[i]+","+p.Name[i];
				}
			}
			MainPeers = allPeers;
		}
	} else {
		MainPeers = "0;";
	}
	return MainPeers,MainQPeer;
}

func ApmsQueueMonitor(conn *net.TCPConn, buf []byte,qn string,ApmsConf config.ApmsConfig) string {
	var(
		ra	[]byte;
		queue	string;
	)
	conn.Write([]byte("Action: QueueStatus\nQueue: "+qn+"\n\n"));
	for{
		nr,err := conn.Read(buf);
		if err != nil {
			if err.String() == "EOF" {os.Exit(1);}
			error := config.LogAsterisk(err.String(),ApmsConf.LogFolder)
			fmt.Print(error)
		}
		ra = bytes.Add(ra,buf[0:nr]);
		retorno := bytes.NewBuffer(ra);
		chk := SearchEvent(retorno, "Event: QueueStatusComplete");
		if chk == true { break;}
	}
	bufra := bytes.Split(ra,[]byte("\r\n"),-1);
	for i:=0; i<cap(bufra); i++ {
		chk := bytes.Split(bufra[i],[]byte(": "),-1);
		if cap(chk) == 2 {
			item := bytes.NewBuffer(chk[0]);
			value := bytes.NewBuffer(chk[1]);
			switch item.String() {
				case "Calls":
					queue = value.String()+";";
				case "CallerIDNum":
					queue = queue+value.String();
				case "Wait":
					tm,_ := strconv.Atoi64(value.String());
					queue = queue+","+config.SecondsToTime(tm)+";";
			}
		}
	}
	return queue;
}

func MainMonitor(ApmsConn *net.TCPConn,ApmsBuf []byte,Astcfg config.AstConfig,ApmsConf config.ApmsConfig) (string,string,string){
	MainQueue := ApmsQueueMonitor(ApmsConn,ApmsBuf,Astcfg.Queue,ApmsConf);
	Ramais := ApmsPeers(ApmsConn,ApmsBuf,ApmsConf);
	MainPeers,MainQPeer := Ramais.AllPeers(ApmsConn,ApmsBuf,ApmsConf);
return MainPeers,MainQueue,MainQPeer;
}
